<template>
    <div class="process-designer">
        <div class="bpmn-canvas" ref="bpmn-canvas"></div>
        <el-card class="properties-panel" header="属性面板">
            <el-collapse v-model="activeTab">
                <el-collapse-item name="base">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-info"></i>常规</div>
                    <element-base-info :id-edit-disabled="false" :business-object="elementBusinessObject"
                                       :type="elementType"/>
                </el-collapse-item>
                <el-collapse-item name="condition" v-if="elementType === 'Process'" key="message">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-s-comment"></i>消息与信号</div>
                    <signal-and-massage/>
                </el-collapse-item>
                <el-collapse-item name="condition" v-if="conditionFormVisible" key="condition">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-s-promotion"></i>流转条件</div>
                    <flow-condition :business-object="elementBusinessObject" :type="elementType"/>
                </el-collapse-item>
                <el-collapse-item name="condition" v-if="formVisible" key="form">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-s-order"></i>表单</div>
                    <element-form :id="elementId" :type="elementType"/>
                </el-collapse-item>
                <el-collapse-item name="task" v-if="elementType.indexOf('Task') !== -1" key="task">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-s-claim"></i>任务</div>
                    <element-task :id="elementId" :type="elementType"/>
                </el-collapse-item>
                <el-collapse-item name="multiInstance" v-if="elementType.indexOf('Task') !== -1" key="multiInstance">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-s-help"></i>多实例</div>
                    <element-multi-instance :business-object="elementBusinessObject" :type="elementType"/>
                </el-collapse-item>
                <el-collapse-item name="listeners" key="listeners">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-message-solid"></i>执行监听器</div>
                    <element-listeners :id="elementId" :type="elementType"/>
                </el-collapse-item>
                <el-collapse-item name="taskListeners" v-if="elementType === 'UserTask'" key="taskListeners">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-message-solid"></i>任务监听器</div>
                    <user-task-listeners :id="elementId" :type="elementType"/>
                </el-collapse-item>
                <el-collapse-item name="extensions" key="extensions">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-circle-plus"></i>扩展属性</div>
                    <element-properties :id="elementId" :type="elementType"/>
                </el-collapse-item>
                <el-collapse-item name="other" key="other">
                    <div slot="title" class="panel-tab__title"><i class="el-icon-s-promotion"></i>其他</div>
                    <element-other-config :id="elementId"/>
                </el-collapse-item>
            </el-collapse>
        </el-card>

    </div>
</template>

<script>
    //引入BpmnModeler
    import BpmnModeler from "bpmn-js/lib/Modeler"
    //兼容activiti
    import activitiModdleDescriptor from './activiti.json'

    import ElementBaseInfo from "./base/ElementBaseInfo";
    import ElementOtherConfig from "./other/ElementOtherConfig";
    import ElementTask from "./task/ElementTask";
    import ElementMultiInstance from "./multi-instance/ElementMultiInstance";
    import FlowCondition from "./flow-condition/FlowCondition";
    import SignalAndMassage from "./signal-message/SignalAndMessage";
    import ElementListeners from "./listeners/ElementListeners";
    import ElementProperties from "./properties/ElementProperties";
    import ElementForm from "./form/ElementForm";
    import UserTaskListeners from "./listeners/UserTaskListeners";
    /* 基础样式 */
    import 'bpmn-js/dist/assets/diagram-js.css';
    import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
    import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
    import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';

    export default {
        name: "ProcessDesigner",
        components: {
            UserTaskListeners,
            ElementForm,
            ElementProperties,
            ElementListeners,
            SignalAndMassage,
            FlowCondition,
            ElementMultiInstance,
            ElementTask,
            ElementOtherConfig,
            ElementBaseInfo
        },
        componentName: "ProcessDesigner",
        props: {
            id: String,
            prefix: {
                type: String,
                default: "activiti"
            },
        },
        provide() {
            return {
                prefix: this.prefix,
                width: 480
            };
        },
        data() {
            return {
                activeTab: "base",
                elementId: "",
                elementType: "",
                elementBusinessObject: {}, // 元素 businessObject 镜像，提供给需要做判断的组件使用
                conditionFormVisible: false, // 流转条件设置
                formVisible: false // 表单配置
            }
        },
        watch: {
            elementId: {
                handler() {
                    //this.activeTab = "base";
                }
            }
        },
        mounted() {
            this.initBpmnModeler();
        },
        methods: {
            initBpmnModeler() {
                if (this.bpmnModeler) return;
                this.bpmnModeler = new BpmnModeler({
                    container: this.$refs["bpmn-canvas"],
                    keyboard: {bindTo: document},
                    moddleExtensions: {activiti: activitiModdleDescriptor}
                });
                this.createNewDiagram();
                window.bpmnInstances = {
                    modeler: this.bpmnModeler,
                    modeling: this.bpmnModeler.get("modeling"),
                    moddle: this.bpmnModeler.get("moddle"),
                    eventBus: this.bpmnModeler.get("eventBus"),
                    bpmnFactory: this.bpmnModeler.get("bpmnFactory"),
                    elementRegistry: this.bpmnModeler.get("elementRegistry"),
                    replace: this.bpmnModeler.get("replace"),
                    selection: this.bpmnModeler.get("selection")
                };
                this.$emit("init-finished", this.bpmnModeler);
                this.initModelListeners();
                this.getActiveElement();
            },
            initModelListeners() {
                const EventBus = this.bpmnModeler.get("eventBus");
                const that = this;
                // 注册需要的监听事件, 将. 替换为 - , 避免解析异常
                /*this.events.forEach(event => {
                  EventBus.on(event, function(eventObj) {
                    let eventName = event.replace(/\./g, "-");
                    let element = eventObj ? eventObj.element : null;
                    that.$emit(eventName, element, eventObj);
                  });
                });*/
                // 监听图形改变返回xml
                EventBus.on("commandStack.changed", async event => {
                    try {
                        this.recoverable = this.bpmnModeler.get("commandStack").canRedo();
                        this.revocable = this.bpmnModeler.get("commandStack").canUndo();
                        let {xml} = await this.bpmnModeler.saveXML({format: true});
                        this.$emit("commandStack-changed", event);
                        this.$emit("input", xml);
                        this.$emit("change", xml);
                    } catch (e) {
                        console.error(`[Process Designer Warn]: ${e.message || e}`);
                    }
                });
                // 监听视图缩放变化
                this.bpmnModeler.on("canvas.viewbox.changed", ({viewbox}) => {
                    this.$emit("canvas-viewbox-changed", {viewbox});
                    const {scale} = viewbox;
                    this.defaultZoom = Math.floor(scale * 100) / 100;
                });
            },
            /* 创建新的流程图 */
            async createNewDiagram(id) {
                if (id) {

                } else {
                    await this.bpmnModeler.createDiagram();
                }
            },
            getActiveElement() {
                // 初始第一个选中元素 bpmn:Process
                this.initFormOnChanged(null);
                this.bpmnModeler.on("import.done", e => {
                    this.initFormOnChanged(null);
                });
                // 监听选择事件，修改当前激活的元素以及表单
                this.bpmnModeler.on("selection.changed", ({newSelection}) => {
                    this.initFormOnChanged(newSelection[0] || null);
                });
                this.bpmnModeler.on("element.changed", ({element}) => {
                    // 保证 修改 "默认流转路径" 类似需要修改多个元素的事件发生的时候，更新表单的元素与原选中元素不一致。
                    if (element && element.id === this.elementId) {
                        this.initFormOnChanged(element);
                    }
                });
            },
            // 初始化数据
            initFormOnChanged(element) {
                let activatedElement = element;
                if (!activatedElement) {
                    activatedElement =
                        window.bpmnInstances.elementRegistry.find(el => el.type === "bpmn:Process") ??
                        window.bpmnInstances.elementRegistry.find(el => el.type === "bpmn:Collaboration");
                }
                if (!activatedElement) return;
                console.log(`
              ----------
      select element changed:
                id:  ${activatedElement.id}
              type:  ${activatedElement.businessObject.$type}
              ----------
              `);
                console.log("businessObject: ", activatedElement.businessObject);
                window.bpmnInstances.bpmnElement = activatedElement;
                this.bpmnElement = activatedElement;
                this.elementId = activatedElement.id;
                this.elementType = activatedElement.type.split(":")[1] || "";
                this.elementBusinessObject = JSON.parse(JSON.stringify(activatedElement.businessObject));
                this.conditionFormVisible = !!(
                    this.elementType === "SequenceFlow" &&
                    activatedElement.source &&
                    activatedElement.source.type.indexOf("StartEvent") === -1
                );
                this.formVisible = this.elementType === "UserTask" || this.elementType === "StartEvent";
            },
            beforeDestroy() {
                window.bpmnInstances = null;
            }
        }
    }
</script>

<style scoped>
    .process-designer {
        height: 100%;
        overflow: hidden;
    }

    .bpmn-canvas {
        height: 100%;
        width: 100%;
        display: inline-block;
    }

    /deep/ .djs-container {
        width: calc(100% - 450px) !important;
        margin-left: 48px;
        position: initial !important;
    }

    /deep/ .bpmn-canvas .djs-palette {
        left: 0;
        top: 0;
        height: 100%;
    }

    /deep/ .bpmn-canvas .djs-direct-editing-parent {
        background-color: transparent !important;
    }

    /deep/ .bpmn-canvas .djs-direct-editing-content {
        padding: 5px 7px !important;
        min-height: 24px;
    }
    .properties-panel {
        position: absolute;
        width: 400px;
        height: calc(100% - 2px);
        right: 0;
        top: 0;
        background: #f8f8f8;
    }
    /deep/.properties-panel .el-card__header{
        padding: 10px;
    }
    /deep/.properties-panel .el-card__body{
        padding: 0;
        height: calc(100% - 42px);
        overflow: auto;
    }
    /deep/.properties-panel .el-collapse-item__header{
        padding-left: 10px;
        border-bottom: 1px solid #EBEEF5;
        background: #f8f8f8;
    }
    /deep/.properties-panel .el-collapse-item__content{
        padding: 15px;
    }
</style>